<?php



/**

 * ECSHOP ZIP 处理类

 * ============================================================================

 *  版权所有 2015-2018 科技有限公司，并保留所有权利。

 * 网站地址: #;

 * ----------------------------------------------------------------------------

 * 仅供学习交流使用，如需商用请购买正版版权。不承担任何法律责任。

 * 踏踏实实做事，堂堂正正做人。

 * ============================================================================

 * $Author: derek $

 * $Id: cls_phpzip.php 17217 2011-01-19 06:29:08Z derek $

*/



if (!defined('IN_ECS'))

{

    die('Hacking attempt');

}



class PHPZip

{

    function zip($dir, $zipfilename, $drop=false)

    {

        if (substr($dir, -1) != '/')

        {

            $dir = ($dir == '') ? './' : $dir . '/';

        }



        if (@function_exists('gzcompress'))

        {

            $curdir = getcwd();

            if (is_array($dir))

            {

                $filelist = $dir;

            }

            else

            {

                $filelist = $this -> get_filelist($dir);

            }



            if ((!empty($dir)) && (!is_array($dir))&&(file_exists($dir)))

            {

                chdir($dir);

            }

            else

            {

                chdir($curdir);

            }



            if (count($filelist) > 0)

            {

                foreach ($filelist AS $filename)

                {

                    if (is_file($filename))

                    {

                        $fd = fopen ($filename, 'rb');

                        $content = fread ($fd, filesize ($filename));

                        fclose ($fd);



                        if (is_array($dir))

                        {

                            $filename = basename($filename);

                        }

                        $this -> add_file($content, $filename);



                        if ($drop)

                        {

                            @unlink($filename);

                        }

                    }

                }

                $out = $this -> file();



                chdir($curdir);

                $fp = fopen($zipfilename, 'wb');

                fwrite($fp, $out, strlen($out));

                fclose($fp);

            }



            return 1;

        }

        else

        {

            return 0;

        }

    }



    function get_filelist($dir)

    {

        $file = array();

        $dir = rtrim($dir,'/');

        if (file_exists($dir))

        {

            $args = func_get_args();

            $pref = isset($args[1]) ? $args[1] : '';



            $dh = opendir($dir);

            while (($files = readdir($dh)) !== false)

            {

                if (($files != '.') && ($files != '..'))

                {

                    if (is_dir($dir .'/'. $files))

                    {

                        $file = array_merge($file, $this -> get_filelist($dir .'/'. $files, "$pref$files/"));

                    }

                    else

                    {

                        $file[] = $pref . $files;

                    }

                }

            }

            closedir($dh);

        }



        return $file;

    }



    var $datasec      = array();

    var $ctrl_dir     = array();

    var $eof_ctrl_dir = "\x50\x4b\x05\x06\x00\x00\x00\x00";

    var $old_offset   = 0;



    /**

     * Converts an Unix timestamp to a four byte DOS date and time format (date

     * in high two bytes, time in low two bytes allowing magnitude comparison).

     *

     * @param  integer  the current Unix timestamp

     *

     * @return integer  the current date in a four byte DOS format

     *

     * @access private

     */

    function unix2DosTime($unixtime = 0)

    {

        $timearray = ($unixtime == 0) ? getdate() : getdate($unixtime);



        if ($timearray['year'] < 1980) {

            $timearray['year']    = 1980;

            $timearray['mon']     = 1;

            $timearray['mday']    = 1;

            $timearray['hours']   = 0;

            $timearray['minutes'] = 0;

            $timearray['seconds'] = 0;

        } // end if



        return (($timearray['year'] - 1980) << 25) | ($timearray['mon'] << 21) | ($timearray['mday'] << 16) |

                ($timearray['hours'] << 11) | ($timearray['minutes'] << 5) | ($timearray['seconds'] >> 1);

    } // end of the 'unix2DosTime()' method



    /**

     * Adds "file" to archive

     *

     * @param  string   file contents

     * @param  string   name of the file in the archive (may contains the path)

     * @param  integer  the current timestamp

     *

     * @access public

     */

    function add_file($data, $name, $time = 0)

    {

        $name     = str_replace('\\', '/', $name);



        $dtime    = dechex($this->unix2DosTime($time));

        $hexdtime = '\x' . $dtime[6] . $dtime[7]

                  . '\x' . $dtime[4] . $dtime[5]

                  . '\x' . $dtime[2] . $dtime[3]

                  . '\x' . $dtime[0] . $dtime[1];

        eval('$hexdtime = "' . $hexdtime . '";');



        $fr = "\x50\x4b\x03\x04";

        $fr .= "\x14\x00";            // ver needed to extract

        $fr .= "\x00\x00";            // gen purpose bit flag

        $fr .= "\x08\x00";            // compression method

        $fr .= $hexdtime;             // last mod time and date



        // "local file header" segment

        $unc_len = strlen($data);

        $crc     = crc32($data);

        $zdata   = gzcompress($data);

        $c_len   = strlen($zdata);

        $zdata   = substr(substr($zdata, 0, strlen($zdata) - 4), 2); // fix crc bug

        $fr      .= pack('V', $crc);             // crc32

        $fr      .= pack('V', $c_len);           // compressed filesize

        $fr      .= pack('V', $unc_len);         // uncompressed filesize

        $fr      .= pack('v', strlen($name));    // length of filename

        $fr      .= pack('v', 0);                // extra field length

        $fr      .= $name;



        // "file data" segment

        $fr .= $zdata;



        // "data descriptor" segment (optional but necessary if archive is not

        // served as file)

        $fr .= pack('V', $crc);                 // crc32

        $fr .= pack('V', $c_len);               // compressed filesize

        $fr .= pack('V', $unc_len);             // uncompressed filesize



        // add this entry to array

        $this -> datasec[] = $fr;

        $new_offset        = strlen(implode('', $this->datasec));



        // now add to central directory record

        $cdrec = "\x50\x4b\x01\x02";

        $cdrec .= "\x00\x00";                // version made by

        $cdrec .= "\x14\x00";                // version needed to extract

        $cdrec .= "\x00\x00";                // gen purpose bit flag

        $cdrec .= "\x08\x00";                // compression method

        $cdrec .= $hexdtime;                 // last mod time & date

        $cdrec .= pack('V', $crc);           // crc32

        $cdrec .= pack('V', $c_len);         // compressed filesize

        $cdrec .= pack('V', $unc_len);       // uncompressed filesize

        $cdrec .= pack('v', strlen($name) ); // length of filename

        $cdrec .= pack('v', 0 );             // extra field length

        $cdrec .= pack('v', 0 );             // file comment length

        $cdrec .= pack('v', 0 );             // disk number start

        $cdrec .= pack('v', 0 );             // internal file attributes

        $cdrec .= pack('V', 32 );            // external file attributes - 'archive' bit set



        $cdrec .= pack('V', $this -> old_offset ); // relative offset of local header

        $this -> old_offset = $new_offset;



        $cdrec .= $name;



        // optional extra field, file comment goes here

        // save to central directory

        $this -> ctrl_dir[] = $cdrec;

    } // end of the 'add_file()' method



    /**

     * Dumps out file

     *

     * @return  string  the zipped file

     *

     * @access public

     */

    function file()

    {

        $data    = implode('', $this -> datasec);

        $ctrldir = implode('', $this -> ctrl_dir);



        return

            $data .

            $ctrldir .

            $this -> eof_ctrl_dir .

            pack('v', sizeof($this -> ctrl_dir)) .  // total # of entries "on this disk"

            pack('v', sizeof($this -> ctrl_dir)) .  // total # of entries overall

            pack('V', strlen($ctrldir)) .           // size of central dir

            pack('V', strlen($data)) .              // offset to start of central dir

            "\x00\x00";                             // .zip file comment length

    } // end of the 'file()' method

} // end of the 'PHPZip' class



?>